#include "jmutex.h"
#include <atomic>

#ifdef _MSC_VER
# pragma warning(disable:26110)
#endif

namespace JXQ
{

class JMultiMutexPirvate
{
public:
	JMultiMutexPirvate(bool m_autoUnlock);
	~JMultiMutexPirvate();

public:
	std::mutex m_mutex;
	std::atomic_uint m_counter;
	std::atomic_bool m_autoUnlock;
};

JMultiMutexPirvate::JMultiMutexPirvate(bool autoUnlock) :
	m_counter(0),
	m_autoUnlock(autoUnlock)
{

}

JMultiMutexPirvate::~JMultiMutexPirvate()
{
	if( m_autoUnlock )
		m_mutex.unlock();
}

/*------------------------------------------------------------------------------*/

JMultiMutex::JMultiMutex(bool autoUnlock) :
	d_ptr(new JMultiMutexPirvate(autoUnlock))
{

}

JMultiMutex::~JMultiMutex()
{
	delete d_ptr;
}

void JMultiMutex::lock(bool block)
{
	++d_ptr->m_counter;
	if( block )
		d_ptr->m_mutex.lock();
	else
		J_UNUSED(d_ptr->m_mutex.try_lock());
}

bool JMultiMutex::tryLock()
{
	++d_ptr->m_counter;
	bool res;
	if( (res = d_ptr->m_mutex.try_lock()) == false )
		--d_ptr->m_counter;
	return res;
}

void JMultiMutex::unlock()
{
	if( --d_ptr->m_counter == 0 )
		d_ptr->m_mutex.unlock();
}

void JMultiMutex::setAutoUnlock(bool autoUnlock)
{
	d_ptr->m_autoUnlock = autoUnlock;
}

bool JMultiMutex::autoUnlock() const
{
	return d_ptr->m_autoUnlock;
}

} //namespace JXQ
